package br.com.projetoia.dama;

import java.util.ArrayList;
import java.util.List;

import br.com.projetoia.dama.enums.WalkerTypeEnum;
import br.com.projetoia.dama.exception.GameException;

public class MiniMax {

	private Board board;

	public MiniMax(Board board) {
		this.board = board;
	}

	public Board getBoard() {
		return this.board;
	}

	public void setBoard(Board board) {
		this.board = board;
	}

	public int evaluation(WalkerTypeEnum walkerType, Board board) throws GameException {
		int value = 0;

		List<Walker> walkers;
		if (walkerType.equals(WalkerTypeEnum.BLACK)) {
			walkers = board.getBlackWalkers();
		} else {
			walkers = board.getWhiteWalkers();
		}

		for (Walker walker : walkers) {
			Position position = walker.getPosition();
			House house = board.getHouse(position.getLine(), position.getColumn());

			value += house.getValue() * walker.getValue();
		}

		return value;
	}

	/**
	 * Retorna a lista de movimentos possiveis.
	 * 
	 * @param walker
	 * @return
	 */
	public List<Position> generateMovement(Walker walker) {
		List<Position> positionList = new ArrayList<Position>();
		Position position = walker.getPosition();
		Board board = this.board;

		positionList = this.getSuccessors(position, board, walker.getType());

		return positionList;

	}

	/**
	 * Obtem as posições sucessores em relação a posição atual. TODO refatorar
	 * este metodo
	 * 
	 * @param position
	 * @param board
	 * @return
	 */
	private List<Position> getSuccessors(Position position, Board currentBoard,
			WalkerTypeEnum walkerType) {

		List<Position> positionList = new ArrayList<Position>();

		int lineIncrement = walkerType.equals(WalkerTypeEnum.WHITE) ? 1 : -1;

		Position rightPosition = new Position(position.getLine() + lineIncrement,
				position.getColumn() + 1);
		Position leftPosition = new Position(position.getLine() + lineIncrement,
				position.getColumn() - 1);

		try {
			if (currentBoard.isValidMoveTo(rightPosition.getLine(), rightPosition.getColumn())) {
				positionList.add(rightPosition);
			} else {
				try {
					House house = currentBoard.getHouse(rightPosition.getLine(),
							rightPosition.getColumn());

					if (!house.getWalker().equals(walkerType)) {
						Position newRightPosition = new Position(rightPosition.getLine()
								+ lineIncrement, rightPosition.getColumn() + 1);

						if (currentBoard.isValidMoveTo(newRightPosition.getLine(),
								newRightPosition.getColumn())) {
							positionList.add(newRightPosition);
						}
					}
				} catch (Exception e) {
					// TODO: handle exception
				}
			}

			if (currentBoard.isValidMoveTo(leftPosition.getLine(), leftPosition.getColumn())) {
				positionList.add(leftPosition);
			} else {
				try {
					House house = currentBoard.getHouse(leftPosition.getLine(),
							leftPosition.getColumn());

					if (!house.getWalker().equals(walkerType)) {
						Position newLeftPosition = new Position(leftPosition.getLine()
								+ lineIncrement, leftPosition.getColumn() + 1);

						if (currentBoard.isValidMoveTo(newLeftPosition.getLine(),
								newLeftPosition.getColumn())) {
							positionList.add(newLeftPosition);
						}
					}

				} catch (Exception e) {

				}
			}
		} catch (GameException e) {

			e.printStackTrace();
		}

		return positionList;

	}

	public BestMovement max(WalkerTypeEnum walkerType, Board curBoard, Integer depth)
			throws GameException, CloneNotSupportedException {

		List<Walker> walkers = new ArrayList<Walker>();
		Integer mostValue = null;
		Position bestPosition = null;
		BestMovement bestMovement = new BestMovement();

		walkers = curBoard.getWalkerCanBeMove(walkerType);

		WalkerTypeEnum otherPlayer = walkerType.equals(WalkerTypeEnum.WHITE) ? WalkerTypeEnum.BLACK
				: WalkerTypeEnum.WHITE;

		for (Walker walker : walkers) {
			List<Position> successors = this.getSuccessors(walker.getPosition(), curBoard,
					walkerType);
			for (Position position : successors) {
				Board tempBoard = new Board(curBoard.getBoard());

				House[][] currentBoard = curBoard.getBoard();

				moveWalker(walker, position, currentBoard);

				if (depth > 0) {
					this.max(otherPlayer, curBoard, depth - 1);
				}

				// curBoard.printBoard();

				int evaluationPlayer1 = this.evaluation(walkerType, curBoard);
				int evaluationPLayer2 = this.evaluation(otherPlayer, curBoard);
				int evaluationBoard = evaluationPlayer1 - evaluationPLayer2;

				curBoard = tempBoard;

				if (mostValue == null || evaluationBoard >= mostValue) {
					mostValue = evaluationBoard;
					bestPosition = position;

					bestMovement.setSource(walker.getPosition());
					bestMovement.setDestination(bestPosition);
				}

			}
		}

		return bestMovement;
	}

	private void moveWalker(Walker walker, Position position, House[][] currentBoard) {
		currentBoard[position.getLine()][position.getColumn()].setWalker(walker);
		currentBoard[walker.getPosition().getLine()][walker.getPosition().getColumn()]
				.setWalker(null);
		walker.setPosition(position);
	}
}
